#ifndef MQSERVER_MQ_CONNECTION_HPP_
#define MQSERVER_MQ_CONNECTION_HPP_
#include "mq_channel.hpp"
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>

namespace mqserver 
{
// Connection: 提供创建/删除信道的功能
class Connection
{
public:
    Connection(const ProtobufCodecPtr& codec,
            const muduo::net::TcpConnectionPtr& conn,
            const VirtualHostPtr& host, 
            const ConsumerManagerPtr& cmp,
            const pool::ThreadPoolPtr& pool)
        : conn_(conn), codec_(codec), consumer_mg_(cmp), host_(host), pool_(pool)
        , channel_mg_(std::make_shared<ChannelManager>())
    {}
    void openChannel(const openChannelRequestPtr& req)
    {
        bool ret = channel_mg_->openChannel(req->channel_id(), codec_, conn_, host_, consumer_mg_, pool_);
        if(!ret) LOG_DEBUG << "the channel ID is duplicated when a channel is created.\n";
        // LOG_DEBUG << "the channel[" << req->channel_id() << "] create success.\n";
        basicResponse(ret, req->rid(), req->channel_id());
    } 
    void closeChannel(const closeChannelRequestPtr& req)
    {
        channel_mg_->closeChannel(req->channel_id());
        basicResponse(true, req->rid(), req->channel_id());
    }
    ChannelPtr getChannel(const std::string& channel_id)
    {
        return channel_mg_->getChannel(channel_id);
    }
private:
    void basicResponse(bool ok, const std::string& rid, const std::string& channel_id)
    {
        proto::protocol::basicCommonResponse resp;
        resp.set_rid(rid);
        resp.set_channel_id(channel_id);
        resp.set_ok(ok);
        codec_->send(conn_, resp);
    }
private:    
    ConsumerPtr consumer_;                  // 信道关联的消费者
    muduo::net::TcpConnectionPtr conn_;     // 通信连接
    ProtobufCodecPtr codec_;                // protobuf协议处理句柄
    ConsumerManagerPtr consumer_mg_;                // 消费者管理句柄
    VirtualHostPtr host_;                   // 虚拟机句柄
    pool::ThreadPoolPtr pool_;             
    ChannelManagerPtr channel_mg_;           // 信道管理句柄
};

using ConnectionPtr = std::shared_ptr<Connection>;

// ConnectionManager: 连接管理类/封装muduo库的Connection(连接的增删查)
class ConnectionManager
{
public:
    ConnectionManager() = default;
    void newConnection(const ProtobufCodecPtr& codec,
            const muduo::net::TcpConnectionPtr& conn,
            const VirtualHostPtr& host, 
            const ConsumerManagerPtr& cmp,
            const pool::ThreadPoolPtr& pool)
    {
        std::lock_guard<std::mutex> lock(mtx_);
        if(existsConnection(conn)) return;
        auto self_conn = std::make_shared<Connection>(codec, conn, host, cmp, pool);
        conns_.emplace(conn, self_conn);
    }
    void deleteConnection(const muduo::net::TcpConnectionPtr& conn)
    {
        std::lock_guard<std::mutex> lock(mtx_);
        conns_.erase(conn);
    }
    ConnectionPtr getConnection(const muduo::net::TcpConnectionPtr& conn)
    {
        std::lock_guard<std::mutex> lock(mtx_);
        return existsConnection(conn) ? conns_[conn] : ConnectionPtr();
    }
private:
    bool existsConnection(const muduo::net::TcpConnectionPtr& conn)
    {
        return conns_.find(conn) != conns_.end();
    }
private:
    std::mutex mtx_;
    std::unordered_map<muduo::net::TcpConnectionPtr, ConnectionPtr> conns_;
};

using ConnectionManagerPtr = std::shared_ptr<ConnectionManager>;

}


#endif